package org.yoshiori.lingr.bot;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yoshiori.lingr.api.Lingr;
import org.yoshiori.lingr.api.LingrObserveException;
import org.yoshiori.lingr.api.ObserveEvent;

/**
 * @author yoshiori
 * 
 */
public class LingrBot {

	private static final Log log = LogFactory.getLog(LingrBot.class);

	private final String apiKey;

	private final String room;

	private final Lingr lingr;

	private String email;

	private String password;

	private Set<ObserverListener> observerListeners = new HashSet<ObserverListener>();

	private Executor executor = Executors.newCachedThreadPool();

	private boolean isAlive = true;

	/**
	 * @param botName
	 * @param room
	 * @param apiKey
	 */
	public LingrBot(String botName, String room, String apiKey) {
		this.apiKey = apiKey;
		this.room = room;
		lingr = new Lingr(botName, apiKey);
	}

	/**
	 * @param room
	 * @param apiKey
	 */
	public LingrBot(String room, String apiKey) {
		this.apiKey = apiKey;
		this.room = room;
		lingr = new Lingr(apiKey);
	}

	/**
	 * @param email
	 * @param password
	 */
	public void setAuth(String email, String password) {
		this.email = email;
		this.password = password;
	}

	/**
	 * 
	 */
	public void start() {
		if (room == null || apiKey == null) {
			throw new NullPointerException(" room or apiKey are NULL ");
		}
		new Thread() {
			/*
			 * (non-Javadoc)
			 * 
			 * @see java.lang.Thread#run()
			 */
			@Override
			public void run() {
				while (isAlive) {
					try {
						runBot();
					} catch (Exception e) {
						if (log.isDebugEnabled()) {
							log.debug(e);
						}
						lingr.exit();
						lingr.destroy();
					}
					try {
						Thread.sleep(1000 * 10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

	private void runBot() {
		if (lingr.create()) {
			if (email != null && password != null) {
				lingr.login(email, password);
			}
			if (lingr.enter(room)) {
				while (lingr.isAlive()) {
					try {
						final ObserveEvent event = lingr.observe();
						if (event.getMessages().size() > 0
								|| event.getOccupants().size() > 0) {
							for (final ObserverListener listener : observerListeners) {
								executor.execute(new Thread() {

									/*
									 * (non-Javadoc)
									 * 
									 * @see java.lang.Thread#run()
									 */
									@Override
									public void run() {
										listener.observe(LingrBot.this, event);
									}
								});
							}
						}
					} catch (Exception e) {
						log.debug(e);
						if (e instanceof LingrObserveException) {
							throw (LingrObserveException) e;
						}
					}
				}
			}
		}
	}

	/**
	 * @param message
	 */
	public void say(String message) {
		lingr.say(message);
	}

	/**
	 * 
	 */
	public void stop() {
		isAlive = false;
		lingr.exit();
		lingr.destroy();
	}

	/**
	 * @param listener
	 */
	public void addListener(ObserverListener listener) {
		observerListeners.add(listener);
	}
}
